package com.utils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Blob;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class EntityFactory<T> {
    private Class<T> obj;
    private Object o;

    public EntityFactory(Class<T> obj) throws Exception {
        this.obj = obj;
        this.o = this.obj.newInstance();
    }

    public T startCombine(ResultSet resultSet) throws Exception {
        Field[] fields = this.obj.getDeclaredFields();
        List<String> names = this.dealName(fields);
        Integer index = 0;
        for (Field field : fields) {
            this.setFieldValue(field, names.get(index++), resultSet);
        }
        return (T) o;
    }

    public List<String> dealName(Field[] fields) {
        List<String> names = new ArrayList<>();
        for (Field field : fields) {
            String name = field.getName();
            name = name.substring(0, 1).toUpperCase() + name.substring(1);
            names.add("set" + name);
        }
        return names;
    }

    public void setFieldValue(Field field, String methodName, ResultSet resultSet) throws Exception {
        String type = field.getType().getSimpleName();
        if (type.equals("Integer")) {
            Integer data = resultSet.getInt(field.getName());
            Method method = this.obj.getMethod(methodName, Integer.class);
            method.invoke(this.o, data);
        } else if (type.equals("Double")) {
            Double data = resultSet.getDouble(field.getName());
            Method method = this.obj.getMethod(methodName, Double.class);
            method.invoke(this.o, data);
        } else if (type.equals("String")) {
            String data = resultSet.getString(field.getName());
            Method method = this.obj.getMethod(methodName, String.class);
            method.invoke(this.o, data);
        } else if (type.equals("Date") || type.equals("DateTime")) {
            Date data = resultSet.getDate(field.getName());
            Method method = this.obj.getMethod(methodName, Date.class);
            method.invoke(this.o, data);
        } else if (type.equals("Byte")) {
            Byte data = resultSet.getByte(field.getName());
            Method method = this.obj.getMethod(methodName, Byte.class);
            method.invoke(this.o, data);
        } else if (type.equals("Blob")) {
            Blob data = resultSet.getBlob(field.getName());
            Method method = this.obj.getMethod(methodName, Blob.class);
            method.invoke(this.o, data);
        } else if (type.equals("Boolean")) {
            Boolean data = resultSet.getBoolean(field.getName());
            Method method = this.obj.getMethod(methodName, Boolean.class);
            method.invoke(this.o, data);
        } else {
            EntityFactory entityFactory = new EntityFactory(field.getType());
            Object data = entityFactory.startCombine(resultSet);
            Method method = this.obj.getMethod(methodName, field.getType());
            method.invoke(this.o, data);
        }
    }
}
